package ru.spb.nicetu.altx.mnemo.math.managers;

import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ICellEditorValidator;
import org.eclipse.swt.widgets.Composite;

import ru.spb.nicetu.altx.mnemo.extpoint.valuetypes.AValueTypeComposite;
import ru.spb.nicetu.altx.mnemo.extpoint.valuetypes.ITemplateValueType;

@SuppressWarnings("unchecked")
public class ValueTypeClassManager {

  protected ValueTypeClassManager() {
  }

  private static ValueTypeClassManager instance = new ValueTypeClassManager();

  public static ValueTypeClassManager getInstance() {
    return instance;
  }

  private Map<String, Class> valueTypeClasses = new HashMap<String, Class>();
  private Map<String, String> valueTypeNames = new HashMap<String, String>();


  /**
   * Мапа, отображающая имя класса в ICellEditorValidator. Необходима для
   * хранения ассоциаций типов данных с классом объектов, которые осуществляют
   * проверку корректности ввода значения
   */
  private Map<String, ICellEditorValidator> valueTypeValidators = new HashMap<String, ICellEditorValidator>();

  /**
   * Добавление класса classClass, соответствующего ключу className
   *
   * @param className
   *          - имя класса - ключ
   * @param classClass
   *          - класс, хранящийся по ключу
   */
  public void addValueTypeClass(String className, Class classClass) {
    valueTypeClasses.put(className, classClass);

    try {
      Object o = classClass.newInstance();
      if (o instanceof ITemplateValueType) {
        valueTypeNames.put(className, ((ITemplateValueType) o).getName());
      }
    } catch (InstantiationException e) {
      e.printStackTrace();
    } catch (IllegalAccessException e) {
      e.printStackTrace();
    }
  }

  /**
   * @param className
   *          - имя класса
   * @return класс с именем className или null
   */
  public Class getValueTypeClass(String className) {
    return valueTypeClasses.get(className);
  }

  /**
   * @param className
   *          - имя класса
   * @return null или символическое имя типа данных (вроде "Скаляр") (если класс
   *         найден и класс instanceof ITemplateValueType)
   */
  public String getValueTypeName(String className) {
    return valueTypeNames.get(className);
  }

  public void addValueTypeValidator(String className,
      ICellEditorValidator validator) {
    valueTypeValidators.put(className, validator);
  }

  /**
   * @param className
   *          - имя класса, для которого необходимо получить класс валидатора
   * @return подкласс, реализующий интерфейс ICellEditorValidator,
   *         ассоциированного с классом по имени className
   */
  public ICellEditorValidator getValueTypeCellEditorValidator(String className) {
    return valueTypeValidators.get(className);
  }

  private Map<String, Class> valueComposites = new HashMap<String, Class>();

  public void addCompositeClass(String typeClassName, Class compositeClass) {
    valueComposites.put(typeClassName, compositeClass);
  }

  /**
   * @param typClassName
   *          - имя класса value.getClass().getName();
   * @return расширение файла для сохранения значения
   */
  public AValueTypeComposite getComposite(String typClassName,
      Composite parent, int style) {
    try {
      return (AValueTypeComposite) valueComposites.get(typClassName)
          .getConstructors()[0].newInstance(parent, style);
    } catch (IllegalArgumentException e) {
      e.printStackTrace();
    } catch (SecurityException e) {
      e.printStackTrace();
    } catch (InstantiationException e) {
      e.printStackTrace();
    } catch (IllegalAccessException e) {
      e.printStackTrace();
    } catch (InvocationTargetException e) {
      e.printStackTrace();
    }
    return null;
  }

  /**
   * классы CellEditor-ов по ключу <имя Класса Значения>
   */
  private Map<String, Class<? extends CellEditor>> cellEditors = new HashMap<String, Class<? extends CellEditor>>();

  /**
   * Добавляет класс Editor-а в Менеджер по ключу <имя Класса Значения>
   */
  public void addCellEditorClass(String valueTypeClass,
      Class<? extends CellEditor> editorClass) {
    cellEditors.put(valueTypeClass, editorClass);
  }

  /**
   * @return класс Editor-а из Менеджера по ключу <имя Класса Значения>
   */
  public Class<? extends CellEditor> getCellEditorClass(String valueTypeClass) {
    return cellEditors.get(valueTypeClass);
  }

  /**
   * классы paramLoader-ов по ключу <имя Класса Значения>
   */
  private Map<String, Class<?>> paramConverters = new HashMap<String, Class<?>>();

  public void addParamConverterClass(String valueTypeClass,
      Class<?> paramLoaderClass) {
    paramConverters.put(valueTypeClass, paramLoaderClass);
  }

  public Class<?> getParamConverterClass(String valueTypeClass) {
    return paramConverters.get(valueTypeClass);
  }

  /**
   * классы figure-ов по ключу <имя Класса Значения>
   */
  private Map<String, Class<?>> figures = new HashMap<String, Class<?>>();

  public void addFigureClass(String valueTypeClass, Class<?> figureClass) {
    figures.put(valueTypeClass, figureClass);
  }

  public Class<?> getFigureClass(String valueTypeClass) {
    return figures.get(valueTypeClass);
  }

  /**
   * классы valueValidator-ов по ключу <имя Класса Значения>
   */
  private Map<String, Class<?>> valueValidators = new HashMap<String, Class<?>>();

  public void addValueValidatorClass(String valueTypeClass,
      Class<?> valueValidatorClass) {
    valueValidators.put(valueTypeClass, valueValidatorClass);
  }

  public Class<?> getValueValidatorClass(String valueTypeClass) {
    return valueValidators.get(valueTypeClass);
  }

  /**
   * имена dbAlias-ов по ключу <имя Класса Значения>
   */
  private Map<String, String> dbAliases = new HashMap<String, String>();

  public void addDBAlias(String className, String dbAlias) {
    dbAliases.put(className, dbAlias);
  }

  public String getDBAlias(String valueTypeClass) {
    return dbAliases.get(valueTypeClass);
  }

  /**
   * Добавляет свойство типу
   */
  public void addProperty(String className, String key, String value) {
    getValueTypeProperties(className).put(key, value);
  }

  public String getProperty(String className, String key) {
    return getValueTypeProperties(className).get(key);
  }

  private Map<String, Map<String, String>> allPropertries = new HashMap<String, Map<String, String>>();

  private Map<String, String> getValueTypeProperties(String className) {
    Map<String, String> props = allPropertries.get(className);
    if (props == null) {
      props = new HashMap<String, String>();
      allPropertries.put(className, props);
    }
    return props;
  }

}
